package manager

import (
	"context"
	"github.com/tianjigames/fairy/constants"
	"github.com/topfreegames/pitaya/component"
	constants2 "github.com/topfreegames/pitaya/constants"
	"github.com/topfreegames/pitaya/logger"
	"github.com/topfreegames/pitaya/queue"
	"github.com/topfreegames/pitaya/route"
	"github.com/topfreegames/pitaya/service"
	"github.com/topfreegames/pitaya/util"
	util2 "github.com/tianjigames/fairy/util"
	"reflect"
	"time"
)

var (
	InitGameRoute = route.NewRoute1(constants.CGInitGameRoute)
)

const tickInterval = 50

type (
	IncomingThread struct {
		component.LogicThread
		msgQueue *queue.BaseQueue
	}

	ThreadMessage struct {
		rt *route.Route
		ctx context.Context
		arg interface{}
	}
)

func NewIncomingThread() *IncomingThread {
	p := &IncomingThread{
		LogicThread:component.LogicThread{
			DieChan: make(chan struct{},1),
			Name: constants.IncomingThread,
		},
		msgQueue: queue.NewBaseQueue(reflect.TypeOf(&ThreadMessage{})),
	}

	p.Run = func() {
		start := util2.Now()
		p.processCacheCmd()
		sleep := tickInterval + util2.Now() - start
		if sleep > 0 {
			time.Sleep(time.Duration(sleep)*time.Millisecond)
		}
	}

	return p
}

/**
添加一条消息
 */
func (p *IncomingThread) AddMessage(rt *route.Route,ctx context.Context,arg interface{})  {
	p.msgQueue.Offer(&ThreadMessage{
		rt: rt,
		ctx: ctx,
		arg: arg,
	})
}

/**
处理任务
 */
func (p *IncomingThread) processCacheCmd() {
	for ;p.msgQueue.Size() > 0; {
		e := p.msgQueue.Poll()
		if e != nil {
			p.InvokeMethod(e.Value.(*ThreadMessage))
		}
	}
}

/**
执行方法体
 */
func (p *IncomingThread) InvokeMethod(msg *ThreadMessage) {
	h,err := service.GetHandler(msg.rt)
	if err != nil {
		logger.Log.Errorf("[IncomingThread] InvokeMethod failed,route:%s,error:%s",msg.rt.String(),err.Error())
		return
	}

	args := []reflect.Value{h.Receiver, reflect.ValueOf(msg.ctx)}
	if msg.arg != nil {
		args = append(args, reflect.ValueOf(msg.arg))
	}

	_,err = util.Pcall(h.Method,args)
	if err != nil && err.Error() != constants2.ErrReturnNil.Error() {
		logger.Log.Errorf("[IncomingThread] InvokeMethod failed,route:%s,error:%s",msg.rt.String(),err.Error())
		return
	}
}
